﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Net;
using System.IO;
using Majestic12;


namespace SmartMovieTime
{
    

    class AtMovieTimeExtractor
    {
        public const string BaseUrl = "http://movie.atmovies.com.tw/showtime/";
        private const string QueryTheater = "theater.asp";
        private const string AreaTaipei = "a02";
        private const string AreaTableFileName = "arealist.txt";
        private string dataDir = null;


        public AtMovieTimeExtractor(string dir)
        {
            dataDir = dir;
            
            if(!Directory.Exists(dataDir))
            {
                Directory.CreateDirectory(dataDir);
            }

            HTMLparser parser = Singleton<HTMLparser>.Instance();
            //parser = new HTMLparser();
            parser.SetChunkHashMode(false);
            parser.bKeepRawHTML = false;
            parser.bDecodeEntities = true;
            parser.bAutoExtractBetweenTagsOnly = false;
            parser.bAutoKeepComments = false;
            parser.bAutoKeepScripts = false;
            parser.bCompressWhiteSpaceBeforeTag = true;
            parser.bAutoMarkClosedTagsWithParamsAsOpen = false;
        }

     

        private void DownloadUrl(string url, string localPath)
        {
            
            HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url);

            // Set some reasonable limits on resources used by this request
            request.MaximumAutomaticRedirections = 4;

            // Set credentials to use for this request.
            request.Credentials = CredentialCache.DefaultCredentials;
            HttpWebResponse response = (HttpWebResponse)request.GetResponse();

            // Get the stream associated with the response.
            Stream receiveStream = response.GetResponseStream();

            // Pipes the stream to a higher level stream reader with the required encoding format. 
            StreamReader readStream = new StreamReader(receiveStream, Encoding.Default);

            StreamWriter writeStream = new StreamWriter(localPath, false, Encoding.Default);

            while (!readStream.EndOfStream)
            {
                string line = readStream.ReadLine();
                writeStream.WriteLine(line);
            }

            response.Close();
            readStream.Close();
            writeStream.Close();
        }

        private string ExtractTheaterIdFromLink(string link)
        {
            const string TID = "theater_id=";
            const int TidLength = 6;

            int idxTheaterId = link.IndexOf(TID);
            string theaterId = null;
            if (idxTheaterId > 0)
                theaterId = link.Substring(idxTheaterId + TID.Length, TidLength);
            return theaterId;         
        }


        private void ExtractTheaterInfo(string srcPath, string dstPath)
        {
            HTMLparser parser = Singleton<HTMLparser>.Instance();
            parser.LoadFromFile(srcPath);

            //Init HTML parser
            HTMLchunk oChunk = null;
            parser.SetEncoding(Encoding.Default);

            StreamWriter writeStream = new StreamWriter(dstPath, false, Encoding.Default);
            
            //Extract theater links    
            string area = null;
            bool areaBegin = false;

            bool linkBegin = false;
            string link = null;
            string linkDescription = null;

            while ((oChunk = parser.ParseNext()) != null)
            {
                switch (oChunk.oType)
                {
                    case HTMLchunkType.OpenTag:
                        if (oChunk.sTag == "a")
                        {
                            if (oChunk.sValues[0] != null && oChunk.sValues[0].IndexOf("theater_id") >= 0)
                            {
                                if(linkBegin)
                                {
                                    
                                    writeStream.WriteLine("{0},{1},{2}", area, linkDescription, ExtractTheaterIdFromLink(link));
                                }

                                linkBegin = true;
                                link = oChunk.sValues[0];
                            }
                        }
                        if (oChunk.sTag == "div")
                        {
                            if (oChunk.sValues[0] != null && oChunk.sValues[0].IndexOf("h_area") >= 0)
                            {
                                areaBegin = true;
                            }
                        }
                        break;
                    case HTMLchunkType.CloseTag:
                        if (linkBegin && oChunk.sTag == "a")
                        {
                            linkBegin = false;
                            writeStream.WriteLine("{0},{1},{2}", area, linkDescription, ExtractTheaterIdFromLink(link));
                        }

                        if (areaBegin && oChunk.sTag == "div")
                        {
                            areaBegin = false;
                        }
                        break;
                    case HTMLchunkType.Text:
                        if (linkBegin)
                        {
                            linkDescription = oChunk.oHTML.Trim();
                        }

                        if (areaBegin)
                        {
                            string tmpArea = oChunk.oHTML.Trim();
                          
                            if (tmpArea.Length > 0)
                            {
                                area = tmpArea.Substring(1, tmpArea.Length - 2);
                            }
                        }
                        break;
                }
            }

            writeStream.Close();
        }

        public void ExtractMovieTime(string srcPath, string dstPath)
        {
            HTMLparser parser = Singleton<HTMLparser>.Instance();
            parser.LoadFromFile(srcPath);

            //Init HTML parser
            HTMLchunk oChunk = null;
            parser.SetEncoding(Encoding.Default);

            StreamWriter writeStream = new StreamWriter(dstPath, false, Encoding.Default);

            //
            bool movieNameBegin = false;
   
            bool timeBegin = false;
        

            while ((oChunk = parser.ParseNext()) != null)
            {
                
                switch (oChunk.oType)
                {
                    case HTMLchunkType.OpenTag:
                        if (oChunk.sTag == "div")
                        {
                            if (oChunk.sValues[0] != null && oChunk.sValues[0] == "row-1")
                            {
                                movieNameBegin = true;
                            }
                            else if (oChunk.sValues[0] != null && oChunk.sValues[0] == "time")
                            {
                                timeBegin = true;
                            }
                        }
                        break;
                    case HTMLchunkType.CloseTag:
                        if(oChunk.sTag == "div")
                        {
                            if (timeBegin)
                            {
                                timeBegin = false;
                                writeStream.WriteLine("");
                            }
                        }
                        break;
                    case HTMLchunkType.Text:
                        if (movieNameBegin)
                        {
                            string name = oChunk.oHTML.Trim();

                            if (name.Length > 0)
                            {
                                writeStream.Write(name);
                                movieNameBegin = false;
                            }
                        }
                        if (timeBegin)
                        {
                            string time = oChunk.oHTML.Trim();

                            if (time.Length > 0)
                            {
                                writeStream.Write(",{0}", time);
                            }
                        }
                        break;
                }
            }

            writeStream.Close();
        }

        public static string GetAreaTableFile(string dataDir)
        {
            return string.Format("{0}{1}", dataDir, AreaTableFileName);
        }

        public static string GetTheaterTableFile(string dataDir, string areaId)
        {
            return string.Format("{0}{1}.txt", dataDir, areaId);
        }

        public static string GetMovieTimeTableFile(string dataDir, string areaId, string theaterId)
        {
            return string.Format("{0}{1}_{2}.txt", dataDir, areaId, theaterId);
        }

        public void UpdateMovieTime()
        {
            //Extract area information
            TxtTable<AtMovieAreaRow> areaTable = new TxtTable<AtMovieAreaRow>();
            string areaTableFile = GetAreaTableFile(dataDir);
            areaTable.LoadFromFile(areaTableFile);
            AtMovieAreaRow areaRow = null;
            while ((areaRow = areaTable.ReadNext()) != null)
            {
                if (areaRow.Enabled)
                {
                    string areaId = areaRow.AreaId;

                    //Download theater information
                    string areaUrl = string.Format("{0}theater.asp?area={1}", BaseUrl, areaId);
                    string theaterSrcPage = string.Format("{0}{1}.html", dataDir, areaId);

                    DownloadUrl(areaUrl, theaterSrcPage);

                    //Extract theater information
                    string theaterTableFile = GetTheaterTableFile(dataDir, areaId);
                    ExtractTheaterInfo(theaterSrcPage, theaterTableFile);

                    //Cleanup html
                    File.Delete(theaterSrcPage);

                    //Extract movie time
                    TxtTable<AtMovieTheaterRow> theaterTable = new TxtTable<AtMovieTheaterRow>();
                    theaterTable.LoadFromFile(theaterTableFile);
                    AtMovieTheaterRow row;
                    while ((row = theaterTable.ReadNext()) != null)
                    {
                        string movieTimePage = string.Format("{0}{1}_{2}.html", dataDir, areaId, row.TheaterId);
                        string movieTimeTableFile = GetMovieTimeTableFile(dataDir, areaId, row.TheaterId);
                        string movieTimeUrl = string.Format("{0}showtime.asp?theater_id={1}&area={2}"
                                , BaseUrl, row.TheaterId, areaId);
                        //for each theater, download movie time pag
                        DownloadUrl(movieTimeUrl, movieTimePage);

                        //for each movie time page, extract movie time
                        ExtractMovieTime(movieTimePage, movieTimeTableFile);

                        //Cleanup html
                        File.Delete(movieTimePage);
                    }

                    theaterTable.Close();
                }
            }
        }
    }
}
